using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.IO;
using System.Threading;

namespace SPLogViewer
{
  public partial class MainForm : Form
  {

    #region Members

    DataTable _logDT = null;

    Dictionary<String, List<String>> _filters = new Dictionary<string, List<string>>();

    TailReader _tailReader = new TailReader();

    CheckBox followTailCheckBox = new CheckBox();
    #endregion

    #region Constructor
    public MainForm()
    {
      InitializeComponent();
      InitControls();
      SetupGridView(dgvLog);

      _tailReader.NewLines += this.AddLogRows;

    }

    #endregion


    #region Private Methods

    private void InitControls()
    {
      ToolStripControlHost toolStripHost = new ToolStripControlHost(followTailCheckBox);
      this.toolStrip.Items.Insert(0, toolStripHost);
      this.toolStrip.Items.Insert(0, new ToolStripLabel("Follow tail: "));

      followTailCheckBox.CheckStateChanged += new EventHandler(followTailCheckBox_CheckStateChanged);

      LoadSettings(true);
    }

    void followTailCheckBox_CheckStateChanged(object sender, EventArgs e)
    {
      MoveCursor();
    }

    List<String> GetFilter(String filerName)
    {
      if (!_filters.ContainsKey(filerName))
      {
        _filters[filerName] = new List<string>();
      }
      return _filters[filerName];
    }

    private void BindData()
    {
      //dgvLog.DataSource = _logDT;
      SetFilter();
    }

    private void SetFilter()
    {
      string filter = "";

      if (!String.IsNullOrEmpty(textMessageFilter.Text))
      {
        filter = string.Format("Message LIKE '%{0}%'", textMessageFilter.Text);
      }
      foreach (KeyValuePair<String, List<String>> columnFilter in _filters)
      {
        if (columnFilter.Value.Count > 0)
        {
          if (filter.Length > 0)
          {
            filter += " AND ";
          }
          filter += "(";
          foreach (string f in columnFilter.Value)
          {
            filter += string.Format("{0} = '{1}' OR ", columnFilter.Key, f);
          }
          filter = filter.Substring(0, filter.Length - 3);
          filter += ")";
        }
      }
      _logDT.DefaultView.RowFilter = filter;
    }

    public void LoadLogData(String fileName)
    {
      statusBar1.Text = "File: " + fileName;
      StreamReader sr = new StreamReader(new FileStream(fileName, FileMode.Open, FileAccess.Read, FileShare.ReadWrite | FileShare.Read | FileShare.ReadWrite), true);

      //string[] fields;
      /*String line = sr.ReadLine();

      fields = line.Split(new char[] { '\t' });
      fields = ClearFields(fields); */

      _logDT = CreateLogDT();
      dgvLog.DataSource = _logDT;
      BindData();
      dgvLog.Columns[0].DefaultCellStyle.Format = "dd.MM.yyyy hh:mm:ss";

      _tailReader.Stop();
      _tailReader.Reader = sr;
      _tailReader.Start();


      FileInfo fi = new FileInfo(fileName);
      fileSystemWatcher.Path = fi.Directory.FullName;

    }

    delegate void AddLogRowsDelegate(List<String> lines);
    private void AddLogRows(List<String> lines)
    {
      if (dgvLog.InvokeRequired)
      {
        this.Invoke(new AddLogRowsDelegate(this.AddLogRows), new object[] { lines });
      }
      else
      {
        DataTable dt = _logDT;
        lock (dt)
        {
          foreach (string line in lines)
          {
            
            {
              string[] fields;
              fields = line.Split(new char[] { '\t' });
              fields = ClearFields(fields);


              DataRow row = dt.NewRow();
              for (int i = 0; i < fields.Length; i++)
              {
                {
                  if (i == 0)
                  {
                    DateTime logTime = GetDateTime(fields[i].ToString());
                    row[i] = logTime;
                  }
                  else
                  {
                    row[i] = fields[i];
                  }
                }
              }
              dt.Rows.Add(row);
            }
          }

        }
        BindData();
        MoveCursor();
      }
    }

    private DateTime GetDateTime(object oDateTime)
    {
      string sDate = oDateTime.ToString();
      string date = sDate.Split(' ')[0];
      string time = sDate.Split(' ')[1];

      int year, month, day, hour, minute, second, milisecond;

      year = Convert.ToInt16(date.Split('/')[2]);
      month = Convert.ToInt16(date.Split('/')[0]);
      day = Convert.ToInt16(date.Split('/')[1]);

      hour = Convert.ToInt16(time.Split(':')[0]);
      minute = Convert.ToInt16(time.Split(':')[1]);
      second = Convert.ToInt16(time.Split(':')[2].Split('.')[0]);
      milisecond = Convert.ToInt16(time.Split(':')[2].Split('.')[1].Replace("*", ""));

      DateTime dt = new DateTime(year, month, day, hour, minute, second);
      return dt;
    }

    private DataTable CreateLogDT()
    {
      DataTable dt = new DataTable();
      foreach (Columns column in Enum.GetValues(typeof(Columns)))
      {

        if (column == Columns.Timestamp)
        {
          dt.Columns.Add(column.ToString(), typeof(DateTime));
        }
        else
        {
          dt.Columns.Add(column.ToString());
        }
      }
      return dt;
    }

    private string[] ClearFields(string[] dirtyFields)
    {
      for (int i = 0; i < dirtyFields.Length; i++)
      {
        dirtyFields[i] = dirtyFields[i].Trim();
      }
      return dirtyFields;
    }

    private void SetupGridView(DataGridView dgv)
    {
      dgv.AllowUserToAddRows = false;
      dgv.AllowUserToResizeRows = false;
      dgv.AutoSizeColumnsMode = DataGridViewAutoSizeColumnsMode.Fill;
      dgv.EditMode = DataGridViewEditMode.EditProgrammatically;
      dgv.MultiSelect = false;
      dgv.RowHeadersVisible = false;
      dgv.SelectionMode = DataGridViewSelectionMode.FullRowSelect;
    }

    private void ShowFilter(string columnName)
    {
      frmFilter frm = new frmFilter();
      frm.ProcessFilter = GetFilter(columnName);
      frm.SetFilter(_logDT, columnName);
      frm.SetLocation(Cursor.Position);

      if (frm.ShowDialog() == DialogResult.OK)
      {
        List<String> filter = GetFilter(columnName);
        filter.Clear();
        foreach (object o in frm.chkFilter.CheckedItems)
        {
          filter.Add(o.ToString());
        }
        BindData();
      }
    }

    private void Filter()
    {
      Cursor = Cursors.WaitCursor;
      string selectStr = string.Format("Message LIKE '%{0}%'", textMessageFilter.Text);
      //_logDT.DefaultView.RowFilter = selectStr;
      BindData();
      Cursor = Cursors.Default;
      //dgvLog.Focus();
    }

    private void OpenFile()
    {
      if (openFileDialog1.ShowDialog(this) == DialogResult.OK)
      {
        String fileName = openFileDialog1.FileName;
        LoadLogData(fileName);
      }

    }

    #endregion

    #region EvenHandlers

    private void dgvLog_SelectionChanged(object sender, EventArgs e)
    {
      if (dgvLog.SelectedRows.Count == 1)
      {
        DataRow row = ((DataRowView)dgvLog.SelectedRows[0].DataBoundItem).Row;
        txtMessage.Text = row["Message"].ToString();
      }
    }



    private void dgvLog_CellMouseClick(object sender, DataGridViewCellMouseEventArgs e)
    {
      if (e.Button == MouseButtons.Right)
      {
        if (dgvLog.Columns[e.ColumnIndex].HeaderText == "Message")
        {
          MessageBox.Show(this, "Don't use distinct on 'Message' column!", "Info", MessageBoxButtons.OK, MessageBoxIcon.Information);
          return;
        }
        ShowFilter(dgvLog.Columns[e.ColumnIndex].HeaderText);
      }
    }

    private void btnFilter_Click(object sender, EventArgs e)
    {
      Filter();
    }

    #endregion

    private void txtMessageFilter_KeyPress(object sender, KeyPressEventArgs e)
    {

    }

    private void txtMessageFilter_KeyDown(object sender, KeyEventArgs e)
    {
      if (e.KeyCode == Keys.Down || e.KeyCode == Keys.Up)
      {
        dgvLog.Focus();
      }
    }

    private void openToolStripMenuItem_Click(object sender, EventArgs e)
    {
      OpenFile();
    }

    private void dgvLog_CellFormatting(object sender, DataGridViewCellFormattingEventArgs e)
    {
      DataGridViewRow row = dgvLog.Rows[e.RowIndex];
      DataGridViewCell cell = row.Cells["Level"];
      if (cell.Value != null)
      {
        switch (cell.Value.ToString())
        {
          case "Critical":
          case "Unexpected":
            dgvLog.Rows[e.RowIndex].DefaultCellStyle.BackColor = Color.Red;
            break;
          case "High":
            dgvLog.Rows[e.RowIndex].DefaultCellStyle.ForeColor = Color.DarkRed;
            break;
          case "Verbose":
            dgvLog.Rows[e.RowIndex].DefaultCellStyle.ForeColor = Color.DarkGray;
            break;
          case "Monitorable":
            dgvLog.Rows[e.RowIndex].DefaultCellStyle.ForeColor = Color.DarkOrange;
            break;
        }
      }
    }

    private void MainForm_FormClosing(object sender, FormClosingEventArgs e)
    {
      _tailReader.Stop();
    }

    private void dgvLog_CurrentCellChanged(object sender, EventArgs e)
    {
      CheckFollowTail();
    }

    private void CheckFollowTail()
    {
      if (this.dgvLog.Rows.Count > 1 && this.dgvLog.CurrentRow != null)
      {
        if (this.dgvLog.CurrentRow.Index == dgvLog.Rows.Count - 1)
        {
          followTailCheckBox.Checked = true;
        }
        else
        {
          followTailCheckBox.Checked = false;
        }
      }
    }

    private void MoveCursor()
    {
      if (followTailCheckBox.Checked)
      {
        if (dgvLog.CurrentRow.Index != dgvLog.RowCount - 1)
        {
          dgvLog.CurrentCell = dgvLog.Rows[dgvLog.RowCount - 1].Cells[0];
        }
      }
    }

    private void settingsToolStripMenuItem_Click(object sender, EventArgs e)
    {
      Settings settings = new Settings();
      if (settings.ShowDialog() == DialogResult.OK)
      {
        LoadSettings(false);
      };
    }


    private void LoadSettings(bool startup)
    {
      if (startup)
      {
        followTailCheckBox.Checked = Properties.Settings.Default.FollowTailOnStartup;
      }
      else
      {
      }

      //fileSystemWatcher.Filter = Properties.Settings.Default.logFileMask;

    }

    private void fileSystemWatcher_Created(object sender, FileSystemEventArgs e)
    {
      if (Properties.Settings.Default.switchToNewLog)
      {
        Thread.Sleep(500); // temp
        LoadLogData(e.FullPath);
      }
    }
  }
}
